package com.hotel.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hotel.entity.Member;
import com.hotel.entity.PointsRecord;
import com.hotel.mapper.MemberMapper;
import com.hotel.mapper.PointsRecordMapper;
import com.hotel.service.MemberService;
import com.hotel.service.PointsRecordService;
import com.hotel.vo.PointsRecordVO;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 积分记录服务实现类
 */
@Service
@RequiredArgsConstructor
public class PointsRecordServiceImpl extends ServiceImpl<PointsRecordMapper, PointsRecord> implements PointsRecordService {

    private final MemberService memberService;
    private final MemberMapper memberMapper; // Assuming you might need direct member queries

    @Override
    public Page<PointsRecordVO> getPointsRecordPage(int current, int size, Long memberId, String type) {
        Page<PointsRecord> page = new Page<>(current, size);
        QueryWrapper<PointsRecord> queryWrapper = new QueryWrapper<>();
        if (memberId != null) {
            queryWrapper.eq("member_id", memberId);
        }
        if (StringUtils.hasText(type)) {
            queryWrapper.eq("type", type);
        }
        queryWrapper.orderByDesc("create_time");

        IPage<PointsRecord> pointsRecordPage = this.page(page, queryWrapper);
        Page<PointsRecordVO> voPage = new Page<>(pointsRecordPage.getCurrent(), pointsRecordPage.getSize(), pointsRecordPage.getTotal());

        List<PointsRecordVO> voList = pointsRecordPage.getRecords().stream().map(record -> {
            PointsRecordVO vo = new PointsRecordVO();
            BeanUtils.copyProperties(record, vo);
            Member member = memberService.getById(record.getMemberId());
            if (member != null) {
                vo.setMemberName(member.getName());
                vo.setMemberPhone(member.getPhone());
            }
            return vo;
        }).collect(Collectors.toList());
        voPage.setRecords(voList);
        return voPage;
    }

    @Override
    @Transactional
    public boolean addPointsRecord(Long memberId, String type, Integer points, String source, String orderNo, String description) {
        Member member = memberService.getById(memberId);
        if (member == null) {
            throw new RuntimeException("会员不存在");
        }

        PointsRecord record = new PointsRecord();
        record.setMemberId(memberId);
        record.setType(type);
        record.setPoints(points);
        record.setSource(source);
        record.setOrderNo(orderNo);
        record.setDescription(description);
        record.setCreateTime(LocalDateTime.now());

        boolean saved = this.save(record);
        if (saved) {
            // Update member's total points
            member.setPoints(member.getPoints() + points);
            memberService.updateById(member);
        }
        return saved;
    }

    @Override
    public List<PointsRecordVO> getMemberPointsRecords(Long memberId, int limit) {
        QueryWrapper<PointsRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("member_id", memberId)
                .orderByDesc("create_time")
                .last("LIMIT " + limit);
        List<PointsRecord> records = this.list(queryWrapper);
        return records.stream().map(record -> {
            PointsRecordVO vo = new PointsRecordVO();
            BeanUtils.copyProperties(record, vo);
            Member member = memberService.getById(record.getMemberId());
            if (member != null) {
                vo.setMemberName(member.getName());
                vo.setMemberPhone(member.getPhone());
            }
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public Map<String, Object> getPointsStats(Long memberId) {
        return Collections.emptyMap();
    }

    @Override
    public List<Map<String, Object>> getPointsTrend(Long memberId, String type) {
        return Collections.emptyList();
    }

    @Override
    public Map<String, Object> getPointsStats() {
        Map<String, Object> stats = new HashMap<>();
        // Example: Total points awarded, total points redeemed
        QueryWrapper<PointsRecord> awardedQuery = new QueryWrapper<PointsRecord>().select("sum(points) as total_awarded").gt("points", 0);
        Map<String, Object> awardedResult = getMap(awardedQuery);
        stats.put("total_points_awarded", awardedResult != null ? awardedResult.get("total_awarded") : 0);

        QueryWrapper<PointsRecord> redeemedQuery = new QueryWrapper<PointsRecord>().select("sum(points) as total_redeemed").lt("points", 0);
        Map<String, Object> redeemedResult = getMap(redeemedQuery);
        stats.put("total_points_redeemed", redeemedResult != null ? redeemedResult.get("total_redeemed") : 0);
        
        stats.put("total_records", count());
        return stats;
    }

    @Override
    public List<Map<String, Object>> getPointsTrend(Long days) {
        LocalDate endDate = LocalDate.now();
        LocalDate startDate = endDate.minusDays(days -1);
        return baseMapper.selectPointsTrendByDateRange(startDate, endDate);
    }

    @Override
    public List<Map<String, Object>> getPointsSourceStats() {
        QueryWrapper<PointsRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("source, SUM(points) as total_points, COUNT(*) as record_count")
                    .isNotNull("source")
                    .groupBy("source")
                    .orderByDesc("total_points");
        return listMaps(queryWrapper);
    }

    @Override
    public List<Map<String, Object>> getPointsUsageStats() {
         QueryWrapper<PointsRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("description as usage_type, SUM(points) as total_points, COUNT(*) as record_count")
                    .lt("points",0) // Consider only redemption/usage
                    .isNotNull("description")
                    .groupBy("description")
                    .orderByDesc("total_points");
        return listMaps(queryWrapper);
    }

    @Override
    public List<Map<String, Object>> getMemberPointsRanking(int limit) {
        // This typically requires a join with the member table or a more complex query
        // For simplicity, let's assume Member entity has a 'points' field that is kept up-to-date
        QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id as member_id", "name as member_name", "points as total_points")
                    .orderByDesc("points")
                    .last("LIMIT " + limit);
        return memberMapper.selectMaps(queryWrapper); 
    }

    @Override
    public List<Map<String, Object>> getPointsTypeStats() {
        QueryWrapper<PointsRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("type, SUM(points) as total_points, COUNT(*) as record_count")
                    .groupBy("type")
                    .orderByDesc("total_points");
        return listMaps(queryWrapper);
    }

    @Override
    public List<Map<String, Object>> getMonthlyPointsStats(int months) {
        LocalDate endDate = LocalDate.now();
        LocalDate startDate = endDate.minusMonths(months - 1).withDayOfMonth(1);
        return baseMapper.selectMonthlyPointsStats(startDate, endDate);
    }

    @Override
    public Map<String, Object> getPointsActivityStats(int days) {
        Map<String, Object> activityStats = new HashMap<>();
        LocalDateTime endDate = LocalDateTime.now();
        LocalDateTime startDate = endDate.minusDays(days);

        QueryWrapper<PointsRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.between("create_time", startDate, endDate);
        long activeRecords = count(queryWrapper);
        activityStats.put("active_records_last_" + days + "_days", activeRecords);

        QueryWrapper<PointsRecord> distinctMemberQuery = new QueryWrapper<>();
        distinctMemberQuery.select("DISTINCT member_id")
                           .between("create_time", startDate, endDate);
        long activeMembers = count(distinctMemberQuery);
        activityStats.put("active_members_last_" + days + "_days", activeMembers);

        return activityStats;
    }

    @Override
    public List<Map<String, Object>> getMemberPointsTrend(Long memberId, int days) {
        LocalDate endDate = LocalDate.now();
        LocalDate startDate = endDate.minusDays(days - 1);
        return baseMapper.selectMemberPointsTrendByDateRange(memberId, startDate, endDate);
    }

    // Placeholder for methods that might be in PointsRecordMapper
    // These would be defined in PointsRecordMapper.java interface:
    // List<Map<String, Object>> selectPointsTrendByDateRange(@Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate);
    // List<Map<String, Object>> selectMonthlyPointsStats(@Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate);
    // List<Map<String, Object>> selectMemberPointsTrendByDateRange(@Param("memberId") Long memberId, @Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate);
}
